//
//  GameScene.cpp
//  NinjaTurtle
//
//  Created by Nguyen Tri Chung on 1/7/15.
//
//

#include "GameScene.h"

GameScene::GameScene() {
    this->inialize();
}

GameScene::~GameScene() {
}

void GameScene::onExit() {
    this->removeAllChildren();
}

void GameScene::disposeComponents() {
    this->unscheduleUpdate();
    this->eventListeners->clear();
    
    GameModel* gameModel = GameModel::getInstance();
    gameModel->removeEventListener(this->gameEventListener);
    
    this->_eventDispatcher->removeEventListener(this->touchListener);
    this->_eventDispatcher->removeEventListener(this->keyBoardListener);
}

void GameScene::inialize() {
    GameModel* gameModel = GameModel::getInstance();
    this->gameEventListener = new GameEventListener();
    this->gameEventListener->setHandlerObject(this);
    this->gameEventListener->setHandlerFunction(handler_function(GameScene::processEvent));
    gameModel->addEventListener(this->gameEventListener);
    
    this->touchListener = EventListenerTouchOneByOne::create();
    this->touchListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
    this->touchListener->onTouchMoved = CC_CALLBACK_2(GameScene::onTouchMoved, this);
    this->touchListener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);
    this->touchListener->onTouchCancelled = CC_CALLBACK_2(GameScene::onTouchEnded, this);
    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(this->touchListener, this);
    
    this->keyBoardListener = EventListenerKeyboard::create();
    this->keyBoardListener->onKeyPressed = CC_CALLBACK_2(GameScene::onKeyPress, this);
    this->keyBoardListener->onKeyReleased = CC_CALLBACK_2(GameScene::onKeyRelease, this);
    this->_eventDispatcher->addEventListenerWithSceneGraphPriority(this->keyBoardListener, this);
    
    this->createLayers();
    this->createLayersContent();
}

void GameScene::createLayers() {
    this->mapLayer = Layer::create();
    this->addChild(this->mapLayer);
    
    this->gameLayer = Layer::create();
    this->addChild(this->gameLayer);
    
    this->controllerLayer = new ControllerLayer(this);
    this->addChild(this->controllerLayer);
    
    this->hintLayer = new HintLayer(this);
    this->addChild(this->hintLayer);
    
    this->mainMenu = Menu::create();
    this->mainMenu->setPosition(Point::ZERO);
    this->addChild(this->mainMenu);
    
    this->pauseLayer = new PauseLayer(this);
    this->addChild(this->pauseLayer);
    this->pauseLayer->setVisible(false);
}

void GameScene::createLayersContent() {
    Size winSize = Director::getInstance()->getWinSize();
    
    // Main menu
    {
        MenuItemSprite* pauseButton = CNodeUtil::createButton(FRAME_BUTTON_PAUSE, FRAME_BUTTON_PAUSE);
        pauseButton->setCallback(CC_CALLBACK_1(GameScene::onPauseButtonClick, this));
        pauseButton->setPosition(Point(winSize.width - pauseButton->getContentSize().width / 2 - 10,
                                       winSize.height - pauseButton->getContentSize().height / 2 - 10));
        this->mainMenu->addChild(pauseButton);
        this->pauseLayer->getParentButtons()->pushBack(pauseButton);
    }
    
    // Pause Layer
    this->pauseLayer->getContinueButton()->setCallback(CC_CALLBACK_1(GameScene::onContinueButtonClick, this));
    this->pauseLayer->getRestartButton()->setCallback(CC_CALLBACK_1(GameScene::onRestartButtonClick, this));
    this->pauseLayer->getQuitButton()->setCallback(CC_CALLBACK_1(GameScene::onQuitButtonClick, this));
}

void GameScene::onPauseButtonClick(Ref* sender) {
    bool clickButton = sender == NULL ? false : true;
    GameModel* gameModel = GameModel::getInstance();
    if (gameModel->getGameState() == GS_PLAY ||
        gameModel->getGameState() == GS_LOAD) {
        
        if (clickButton) {
            GameEvent* clickButtonEvent = new GameEvent();
            clickButtonEvent->setEventCode(EVT_CLICK_BUTTON);
            this->fireEvent(clickButtonEvent);
        }
        
        GameEvent* gameEvent = new GameEvent();
        gameEvent->setEventCode(EVT_PAUSE_GAME);
        this->fireEvent(gameEvent);
        
        this->pauseLayer->show();
    }
}

void GameScene::onContinueButtonClick(Ref* sender) {
    GameEvent* clickButtonEvent = new GameEvent();
    clickButtonEvent->setEventCode(EVT_CLICK_BUTTON);
    this->fireEvent(clickButtonEvent);
    
    GameEvent* gameEvent = new GameEvent();
    gameEvent->setEventCode(EVT_RESUME_GAME);
    this->fireEvent(gameEvent);
    
    this->pauseLayer->hide();
}

void GameScene::onRestartButtonClick(Ref* sender) {
    GameEvent* clickButtonEvent = new GameEvent();
    clickButtonEvent->setEventCode(EVT_CLICK_BUTTON);
    this->fireEvent(clickButtonEvent);
    
    GameEvent* gameEvent = new GameEvent();
    gameEvent->setEventCode(EVT_REPLAY_MAP);
    this->fireEvent(gameEvent);
}

void GameScene::onQuitButtonClick(Ref* sender) {
    GameEvent* clickButtonEvent = new GameEvent();
    clickButtonEvent->setEventCode(EVT_CLICK_BUTTON);
    this->fireEvent(clickButtonEvent);
    
    GameEvent* gameEvent = new GameEvent();
    gameEvent->setEventCode(EVT_QUIT_GAME);
    this->fireEvent(gameEvent);
}

void GameScene::processEvent(GameEvent* gameEvent) {
    GameModel* gameModel = GameModel::getInstance();
    if (gameEvent->getEventCode() == EVT_MAP_CREATED) {
        Level* level = gameModel->getCurrentLevel();
        this->gameLayer->setPosition(level->getViewPoint());
        Size winSize = Director::getInstance()->getWinSize();

        CSprite* mapBackground1 = new CSprite();
        mapBackground1->initWithSpriteFrameName(FRAME_BG_1);
        mapBackground1->setPosition(winSize.width / 2, winSize.height / 2);
        this->mapLayer->addChild(mapBackground1);
        
        CSprite* mapBackground2 = new CSprite();
        mapBackground2->initWithSpriteFrameName(FRAME_BG_2);
        mapBackground2->setPosition(winSize.width / 2, winSize.height / 2);
        this->mapLayer->addChild(mapBackground2);
        
        CSprite* mapBackground3 = new CSprite();
        mapBackground3->initWithSpriteFrameName(FRAME_BG_3);
        mapBackground3->setPosition(winSize.width / 2, winSize.height / 2);
        this->mapLayer->addChild(mapBackground3);
        
        char levelStr[20];
        sprintf(levelStr, TXT_LEVEL, level->getLevel());
        Label* labelLevel = CNodeUtil::createLabelTTF(levelStr, 20, FONT_ARCADE);
        labelLevel->setPosition(winSize.width / 2, labelLevel->getContentSize().height / 2 + 5);
        this->addChild(labelLevel, 100);
        
        this->addSpriteToLayer(level->getTurtle(), this->gameLayer, INDEX_TURTLE);
        this->gameLayer->addChild(gameModel->getCurrentLevel()->getMapInfo(), INDEX_TILE);
        for (auto iter = level->getLands()->begin(); iter != level->getLands()->end(); iter++) {
            this->addSpriteToLayer(*iter, this->gameLayer, INDEX_OBJECT_HIGH);
        }
        for (auto iter = level->getTeleportObjects()->begin(); iter != level->getTeleportObjects()->end(); iter++) {
            this->addSpriteToLayer(*iter, this->gameLayer, INDEX_OBJECT);
        }
        for (auto iter = level->getHintObjects()->begin(); iter != level->getHintObjects()->end(); iter++) {
            this->addSpriteToLayer(*iter, this->gameLayer, INDEX_OBJECT);
        }
        for (auto iter = level->getTrapObjects()->begin(); iter != level->getTrapObjects()->end(); iter++) {
            this->addSpriteToLayer(*iter, this->gameLayer, INDEX_OBJECT);
        }
        for (auto iter = level->getEnemyObjects()->begin(); iter != level->getEnemyObjects()->end(); iter++) {
            this->addSpriteToLayer(*iter, this->gameLayer, INDEX_OBJECT);
        }
    } else if (gameEvent->getEventCode() == EVT_NEXT_MAP) {
        if (gameModel->isLastMap()) {
            DataEvent* gameEvent = new DataEvent();
            gameEvent->setEventCode(EVT_COMPLETED_GAME);
            this->fireEvent(gameEvent);
            return;
        }
    } else if (gameEvent->getEventCode() == EVT_RECEIVE_HINT) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        string hint = dataEvent->getArgumentString();
        this->hintLayer->showHint(hint);
    } else if (gameEvent->getEventCode() == EVT_LOSE_HINT) {
        this->hintLayer->hideHint();
    } else if (gameEvent->getEventCode() == EVT_ENEMY_LOST_EQUIPMENT) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        EnemyObj* enemy = (EnemyObj*) dataEvent->getArgumentReference();
        this->removeSprite(enemy);
    } else if (gameEvent->getEventCode() == EVT_NEW_BULLET) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        this->addSpriteToLayer((Obj*) dataEvent->getArgumentReference(), this->gameLayer, INDEX_OBJECT_HIGH);
    } else if (gameEvent->getEventCode() == EVT_LOST_BULLET) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        this->removeSprite((Obj*) dataEvent->getArgumentReference());
    } else if (gameEvent->getEventCode() == EVT_ENEMY_BEING_SHOOTED) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        this->removeSprite((Obj*) dataEvent->getArgumentReference());
    } else if (gameEvent->getEventCode() == EVT_TREE_BEING_CUT) {
        DataEvent* dataEvent = (DataEvent*) gameEvent;
        this->removeSprite((Obj*) dataEvent->getArgumentReference());
    }
    
    this->fireEvent(gameEvent);
}

void GameScene::update(float dt) {
    GameModel* gameModel = GameModel::getInstance();
    if (gameModel->getGameState() == GS_PLAY) {
        this->gameLayer->setPosition(gameModel->getCurrentLevel()->getViewPoint());
        
        Turtle* turtle = gameModel->getCurrentLevel()->getTurtle();
        if (turtle->getEquipment() == EQUIPMENT_WARRIOR) {
            this->controllerLayer->getButtonC()->setVisible(true);
        } else {
            this->controllerLayer->getButtonC()->setVisible(false);
        }
    }
}

void GameScene::onKeyPress(EventKeyboard::KeyCode keyCode, Event* event) {
}

void GameScene::onKeyRelease(EventKeyboard::KeyCode keyCode, cocos2d::Event *event) {
    if (this->pauseLayer->isVisible()) {
        return;
    }
    
    GameModel* gameModel = GameModel::getInstance();
    if (gameModel->getGameState() == GS_PLAY) {
        GameEvent* clickButtonEvent = new GameEvent();
        clickButtonEvent->setEventCode(EVT_CLICK_BUTTON);
        this->fireEvent(clickButtonEvent);
        
        if (keyCode == EventKeyboard::KeyCode::KEY_BACK) {
            GameEvent* gameEvent = new GameEvent();
            gameEvent->setEventCode(EVT_PAUSE_GAME);
            this->fireEvent(gameEvent);
            
            this->pauseLayer->show();
        }
    }
}

bool GameScene::onTouchBegan(Touch* touch, Event* event) {
    return true;
}

void GameScene::onTouchMoved(Touch* touch, Event* event) {
}

void GameScene::onTouchEnded(Touch* touch, Event* event) {
}

void GameScene::onTouchCancelled(Touch* touch, Event* event) {
    this->onTouchEnded(touch, event);
}

void GameScene::addSpriteToLayer(Obj* object, Layer* layer, int index) {
    for (int i = 0; i < object->getSprites()->size(); i++) {
        CSprite* cSprite = (CSprite*) object->getSprites()->at(i);
        cSprite->setPosition(object->getPosition());
        cSprite->setAnchorPoint(object->getBody()->getAnchorPoint());
        cSprite->setFlippedX(object->getBody()->getFlipX());
        layer->addChild(cSprite, index);
    }
}

void GameScene::removeSprite(Obj* object) {
    for (int i = 0; i < object->getSprites()->size(); i++) {
        CSprite* cSprite = (CSprite*) object->getSprites()->at(i);
        cSprite->removeFromParent();
    }
}
